local Class = require('lua.lang.Class')
local LuaValue = require('lua.vm.LuaValue')

--- @class LuaNumber : LuaValue
--- @field v number
local LuaNumber = Class {
	__extends = LuaValue
}

--- @param v number
--- @return LuaNumber
function LuaNumber:new(v)
	--- @type LuaNumber
	local o = {
		v = v
	}
	return setmetatable(o, LuaNumber)
end

LuaNumber.ZERO = LuaNumber:new(0)
LuaNumber.ONE = LuaNumber:new(1)
LuaNumber.MINUS_ONE = LuaNumber:new(-1)

--- @return number
function LuaNumber:type()
	return self.TYPE_NUMBER
end

--- @return string
function LuaNumber:typeName()
	return self.TYPE_NAMES[self:type() + 1]
end

--- @return boolean
function LuaNumber:isNumber()
	return true
end

--- @param value number
--- @return LuaNumber
function LuaNumber:valueOf(value)
	return LuaNumber:new(value)
end

--- @param val LuaValue
--- @return boolean
function LuaNumber:eq_b(val)
	return val:rawEq(self.v)
end

--- @param val number
--- @return boolean
function LuaNumber:rawEq(val)
	return self.v == val
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaNumber:add(rhs)
	return rhs:isNumber() and self:valueOf(self.v + rhs:toNumber()) or LuaValue.add(self, rhs)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaNumber:sub(rhs)
	return rhs:isNumber() and self:valueOf(self.v - rhs:toNumber()) or LuaValue.sub(self, rhs)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaNumber:mul(rhs)
	return rhs:isNumber() and self:valueOf(self.v * rhs:toNumber()) or LuaValue.mul(self, rhs)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaNumber:div(rhs)
	return rhs:isNumber() and self:valueOf(self.v / rhs:toNumber()) or LuaValue.div(self, rhs)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaNumber:mod(rhs)
	return rhs:isNumber() and self:valueOf(self.v % rhs:toNumber()) or LuaValue.mod(self, rhs)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaNumber:pow(rhs)
	return rhs:isNumber() and self:valueOf(self.v ^ rhs:toNumber()) or LuaValue.pow(self, rhs)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaNumber:iDiv(rhs)
	return rhs:isNumber() and self:valueOf(self.v // rhs:toNumber()) or LuaValue.iDiv(self, rhs)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaNumber:bAnd(rhs)
	return rhs:isNumber() and self:valueOf(self.v & rhs:toNumber()) or LuaValue.bAnd(self, rhs)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaNumber:bOr(rhs)
	return rhs:isNumber() and self:valueOf(self.v | rhs:toNumber()) or LuaValue.bOr(self, rhs)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaNumber:bXor(rhs)
	return rhs:isNumber() and self:valueOf(self.v ~ rhs:toNumber()) or LuaValue.bXor(self, rhs)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaNumber:shl(rhs)
	return rhs:isNumber() and self:valueOf(self.v << rhs:toNumber()) or LuaValue.shl(self, rhs)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaNumber:shr(rhs)
	return rhs:isNumber() and self:valueOf(self.v >> rhs:toNumber()) or LuaValue.shr(self, rhs)
end

--- @return LuaValue
function LuaNumber:neg()
	return self:valueOf(-self.v)
end

--- @return LuaValue
function LuaNumber:bNot()
	return self:valueOf(~self.v)
end

--- @return number
function LuaNumber:toNumber()
	return self.v
end

--- @return string
function LuaNumber:toLString()
	return tostring(self.v)
end

return LuaNumber